package core.protocol.impl;

import java.rmi.RemoteException;
import java.util.TreeSet;

import core.api.ClientAPI;
import core.protocol.ProtocolAD;


public class DolevKlaweRodeh  implements ProtocolAD
{
	private final ClientAPI cClient ;
	
	private final TreeSet<Integer> tsNeigbors;
	
	private enum State{
		ACTIF,
		PASIF,
		LOST,
		LEADER;
	}

	State state;
	int myNumber,next;
	int leader,vac;
	
	public DolevKlaweRodeh(ClientAPI client) 
	{
		super();
		this.cClient = client;
		this.tsNeigbors= new TreeSet<Integer>();
		try 
		{
			myNumber = cClient.getId();
			next = -1;
			state = State.PASIF;
			leader = -1;
			vac = -1;
		} 
		catch (RemoteException e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void run() 
	{
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addNeighbour(int i)
	{
		tsNeigbors.add(i);

		//Récupération du premier noeud (fin de boucle)
		Integer high = tsNeigbors.higher(myNumber); 
		if( high != null ){
			//Récupération du noeud suivant
			next = high;
			System.out.println(myNumber + " Changement de suivant  : " + next);
		}else{ 
			//Récupération du premier noeud (fin de boucle)
			next = tsNeigbors.first();
			System.out.println(myNumber + " Changement de suivant  : " + next);
		}
	}
	@Override
	public void removeNeighbour(int i) 
	{
		tsNeigbors.remove(i);
		if( i == next ){
			Integer high = tsNeigbors.higher(myNumber); 
			if( high != null ){
				//Récupération du noeud suivant
				next = high;
				System.out.println(myNumber + " Changement de suivant  : " + next);
			}else{ 
				//Récupération du premier noeud (fin de boucle)
				next = tsNeigbors.first();
				System.out.println(myNumber + " Changement de suivant  : " + next);
			}
		}
	}
	
	public void one(Integer token)
	{
		if(state == State.ACTIF)	
		{
			vac = token;
			if(vac == myNumber)
			{
				System.out.println("Process " + vac + " est le leader ");
				try {
					cClient.setMaster(myNumber, myNumber, vac);
				} 
				catch (RemoteException e3)
				{
					System.out.println("Erreur : setMaster :" + myNumber);
				}
				try 
				{
					cClient.callProtocol(myNumber, next,"small",vac);
					registerLastSend("small",vac);
				} 
				catch (RemoteException e3)
				{
					System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
				}
				leader = vac;
			}
			else
			{
				System.out.println("Process " + vac + " est le numero voisin ");
				try {
					cClient.callProtocol(myNumber, next,"two",vac);
					registerLastSend("two",vac);
				} 
				catch (RemoteException e3)
				{
					System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
				}
			}
		}
		else
		{
			try {
				cClient.callProtocol(myNumber, next,"one",token);
				registerLastSend("one",token);
			} 
			catch (RemoteException e3)
			{
				System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
			}
		}
	}
	public void two(Integer token)
	{
		if(state == State.ACTIF && vac != myNumber)	
		{
			if(vac < myNumber && vac < token)
			{
				myNumber = vac;
			}
			else
			{
				state = State.PASIF;
			}
		}
		else
		{
			try {
				cClient.callProtocol(myNumber, next,"two",token);
				registerLastSend("two",token);
			} 
			catch (RemoteException e3)
			{
				System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
			}
		}
	}
	public void small(Integer token)
	{
		leader = token;
		System.out.println("Process " + leader + " est le leader de "+myNumber);
		try {
			cClient.setMaster(myNumber, myNumber, leader);
		} 
		catch (RemoteException e3)
		{
			System.out.println("Erreur : setMaster :" + myNumber);
		}
		if(vac != myNumber || state != State.ACTIF)
		{
			try {
				cClient.callProtocol(myNumber, next,"small",token);
				registerLastSend("small",token);
			} 
			catch (RemoteException e3)
			{
				System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
			}
		}	
		try 
		{
			myNumber = cClient.getId();
			state = State.PASIF;
			leader = -1;
			vac = -1;
		} 
		catch (RemoteException e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void startElection() 
	{
		System.out.println("Process " + myNumber + " commence l'election ");
		state = State.ACTIF;
		if(leader == -1)
		{
			try {
				cClient.callProtocol(myNumber, next,"one",myNumber);
				registerLastSend("one",myNumber);
			} 
			catch (RemoteException e3)
			{
				System.out.println("Erreur : callProtocol :" + myNumber + " -> " + next);
			}
		}
	}
	


	@Override
	public void timeoutProtocol(int dest) {
		if(lastMethod!=null && lastObjects!=null){
			try {
				cClient.callProtocol(myNumber,next,lastMethod,lastObjects);
			} catch (RemoteException e3) {
				e3.printStackTrace();
			}
		}
	}

	private String lastMethod = null;
	private Object []lastObjects = null;
	
	private void registerLastSend(String method, Object... objects){
		lastMethod = method;
		lastObjects = objects;
	}
}
